<template>
  <!-- 模板部分：定义一个容器元素用于渲染3D场景 -->
  <div ref="container" class="car-road-container"></div>
</template>

<script setup lang="ts">
// 导入Vue 3的Composition API相关函数
import { ref, onMounted, onUnmounted } from 'vue';
// 导入Three.js库，用于创建3D图形
import * as THREE from 'three';

// 创建一个响应式引用，用于存储DOM容器元素
// ref<HTMLElement | null>(null) 表示这个引用可以是HTMLElement类型或者null
const container = ref<HTMLElement | null>(null);

// Three.js相关变量声明
let scene: THREE.Scene;           // 3D场景，包含所有要渲染的对象
let camera: THREE.PerspectiveCamera; // 透视相机，决定如何将3D场景投影到2D屏幕
let renderer: THREE.WebGLRenderer; // WebGL渲染器，负责将3D场景渲染到canvas中
let car: THREE.Group;             // 汽车组，用于将汽车的各个部分组合在一起
let road: THREE.Mesh;             // 道路网格对象
let animationId: number;          // 动画ID，用于控制动画循环

// 初始化Three.js场景的函数
const initThreeJS = (): void => {
  // 检查容器元素是否存在，如果不存在则退出函数
  if (!container.value) {return;}

  // 初始化Three.js场景
  // THREE.Scene() - 创建一个新的3D场景对象
  // 作用：场景是所有3D对象的容器，用于管理要渲染的所有物体、灯光、相机等
  // 参数：无
  // 返回值：THREE.Scene实例
  scene = new THREE.Scene();
  
  // 创建透视相机
  // THREE.PerspectiveCamera() - 创建透视投影相机
  // 作用：模拟人眼视角，近大远小，用于3D场景渲染
  // 参数：
  //   - fov (number): 视野角度，单位度，默认50，这里75度
  //   - aspect (number): 宽高比，窗口宽度除以高度
  //   - near (number): 近裁剪面，距离相机多近开始渲染，默认0.1
  //   - far (number): 远裁剪面，距离相机多远停止渲染，默认1000
  // 返回值：THREE.PerspectiveCamera实例
  camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  
  // 创建WebGL渲染器
  // THREE.WebGLRenderer() - 创建WebGL渲染器对象
  // 作用：使用WebGL技术在canvas上渲染3D场景
  // 参数：
  //   - options (object): 配置选项
  //     - antialias (boolean): 是否开启抗锯齿，true使边缘更平滑
  //   - 其他可选参数：alpha, precision, depth, stencil等
  // 返回值：THREE.WebGLRenderer实例
  renderer = new THREE.WebGLRenderer({ antialias: true });

  // 设置渲染器大小
  // renderer.setSize() - 设置渲染器的输出canvas大小
  // 作用：调整渲染器绘制区域的大小，匹配窗口尺寸
  // 参数：
  //   - width (number): 宽度像素值，这里使用窗口内宽
  //   - height (number): 高度像素值，这里使用窗口内高
  //   - updateStyle (boolean, 可选): 是否更新canvas样式，默认true
  // 返回值：无
  renderer.setSize(window.innerWidth, window.innerHeight);
  // 设置像素比率
  // renderer.setPixelRatio() - 设置设备像素比率
  // 作用：适配高DPI屏幕，防止渲染模糊，提高显示质量
  // 参数：
  //   - ratio (number): 像素比率，通常使用window.devicePixelRatio
  // 返回值：无
  renderer.setPixelRatio(window.devicePixelRatio);
  // 将渲染器canvas添加到DOM
  // container.value.appendChild() - DOM操作方法
  // 作用：将Three.js渲染器的canvas元素添加到页面中显示
  // 参数：
  //   - renderer.domElement: 渲染器的canvas DOM元素
  // 返回值：无
  container.value.appendChild(renderer.domElement);

  // 创建环境光
  // THREE.AmbientLight() - 创建环境光光源
  // 作用：提供均匀的全方向照明，没有阴影，模拟全局环境光
  // 参数：
  //   - color (number/string): 光的颜色，十六进制值(0x404040)或CSS颜色字符串
  //   - intensity (number, 可选): 光强度，默认1.0
  // 返回值：THREE.AmbientLight实例
  const ambientLight: THREE.AmbientLight = new THREE.AmbientLight(0x404040);
  // 将光源添加到场景
  // scene.add() - 将对象添加到场景中
  // 作用：将创建的光源、几何体、网格等对象添加到场景中进行渲染
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为环境光
  // 返回值：无
  scene.add(ambientLight);

  // 创建定向光
  // THREE.DirectionalLight() - 创建定向光源
  // 作用：提供有方向的平行光照，模拟太阳光，会产生阴影
  // 参数：
  //   - color (number/string): 光的颜色，十六进制值(0xffffff)或CSS颜色字符串
  //   - intensity (number, 可选): 光强度，默认1.0，这里0.8
  // 返回值：THREE.DirectionalLight实例
  const directionalLight: THREE.DirectionalLight = new THREE.DirectionalLight(0xffffff, 0.8);
  // 设置光源位置
  // directionalLight.position.set() - 设置光源在3D空间中的位置
  // 作用：确定定向光的来源方向，位置影响光照角度和阴影
  // 参数：
  //   - x (number): X轴坐标，正右负左
  //   - y (number): Y轴坐标，正上负下
  //   - z (number): Z轴坐标，正前负后
  // 返回值：无
  directionalLight.position.set(5, 10, 7.5);
  // 将定向光添加到场景
  // scene.add() - 将对象添加到场景中
  // 作用：将创建的定向光源添加到场景中进行渲染和光照计算
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为定向光
  // 返回值：无
  scene.add(directionalLight);

  // 创建立方体几何体
  // THREE.BoxGeometry() - 创建立方体/长方体几何体
  // 作用：定义道路的3D形状，包含顶点、面、UV坐标等几何信息
  // 参数：
  //   - width (number): X轴方向的宽度，单位为单位长度，这里20
  //   - height (number): Y轴方向的高度，这里0.1（很薄）
  //   - depth (number): Z轴方向的深度，这里5
  //   - widthSegments (number, 可选): 宽度分段数，默认1
  //   - heightSegments (number, 可选): 高度分段数，默认1
  //   - depthSegments (number, 可选): 深度分段数，默认1
  // 返回值：THREE.BoxGeometry实例
  const roadGeometry: THREE.BoxGeometry = new THREE.BoxGeometry(20, 0.1, 5);
  // 创建标准材质
  // THREE.MeshStandardMaterial() - 创建基于物理渲染的标准材质
  // 作用：定义道路表面的外观特性，支持光照、粗糙度、金属度等PBR属性
  // 参数：
  //   - options (object): 材质配置选项
  //     - color (number): 基础颜色，十六进制值(0x333333)表示深灰色
  //     - roughness (number): 粗糙度，0-1之间，0.8表示表面很粗糙
  //     - metalness (number): 金属度，0-1之间，0.2表示轻微金属感
  //     - 其他可选参数：map, normalMap, envMap等
  // 返回值：THREE.MeshStandardMaterial实例
  const roadMaterial: THREE.MeshStandardMaterial = new THREE.MeshStandardMaterial({
    color: 0x333333,    // 颜色：深灰色
    roughness: 0.8,     // 粗糙度：0.8 (0-1之间，值越大表面越粗糙)
    metalness: 0.2,     // 金属度：0.2 (0-1之间，值越大金属感越强)
  });
  // 创建网格对象
  // THREE.Mesh() - 创建网格对象，组合几何体和材质
  // 作用：将几何形状和材质结合，创建可渲染的3D物体
  // 参数：
  //   - geometry (Geometry): 几何体对象，这里为道路几何体
  //   - material (Material): 材质对象，这里为道路材质
  // 返回值：THREE.Mesh实例
  road = new THREE.Mesh(roadGeometry, roadMaterial);
  // 设置道路位置
  // road.position.y - 设置道路在Y轴的位置
  // 作用：调整道路在3D空间中的垂直位置，负值表示向下移动
  // 参数：
  //   - 直接赋值：position.y = -1 表示在Y轴向下移动1个单位
  // 返回值：无
  road.position.y = -1;
  // 将道路添加到场景
  // scene.add() - 将对象添加到场景中
  // 作用：将创建的道路网格对象添加到场景中进行渲染
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为道路网格
  // 返回值：无
  scene.add(road);

  // 创建标记线几何体
  // THREE.BoxGeometry() - 创建立方体几何体
  // 作用：定义道路标记线的3D形状，小型长方体作为车道线
  // 参数：
  //   - width (number): X轴宽度，0.5单位
  //   - height (number): Y轴高度，0.05单位（很薄）
  //   - depth (number): Z轴深度，0.1单位
  // 返回值：THREE.BoxGeometry实例
  const markingGeometry: THREE.BoxGeometry = new THREE.BoxGeometry(0.5, 0.05, 0.1);
  // 创建基础材质
  // THREE.MeshBasicMaterial() - 创建基础材质
  // 作用：定义标记线外观，不受光照影响，始终保持指定颜色
  // 参数：
  //   - options (object): 材质配置选项
  //     - color (number): 颜色，十六进制值(0xffffff)表示白色
  //     - 其他可选参数：wireframe, transparent, opacity等
  // 返回值：THREE.MeshBasicMaterial实例
  const markingMaterial: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff });

  // 使用循环创建多个道路标记线
  // i从-9到9，每次增加2，在x轴上均匀分布标记线
  for (let i = -9; i <= 9; i += 2) {
    // 创建标记线网格对象
    // THREE.Mesh() - 创建网格对象
    // 作用：将标记线几何体和材质结合，创建可渲染的车道线
    // 参数：
    //   - geometry (Geometry): 几何体对象，这里为标记线几何体
    //   - material (Material): 材质对象，这里为标记线材质
    // 返回值：THREE.Mesh实例
    const marking: THREE.Mesh = new THREE.Mesh(markingGeometry, markingMaterial);
    // 设置标记线位置
    // marking.position.set() - 设置标记线在3D空间中的位置
    // 作用：确定每条标记线的具体位置，分布在道路表面上
    // 参数：
    //   - x (number): X轴坐标，根据循环变量i变化，横向分布
    //   - y (number): Y轴坐标，-0.9略高于道路表面(-1)
    //   - z (number): Z轴坐标，0表示在道路中央
    // 返回值：无
    marking.position.set(i, -0.9, 0);
    // 将标记线添加到场景
    // scene.add() - 将对象添加到场景中
    // 作用：将创建的标记线网格对象添加到场景中进行渲染
    // 参数：
    //   - object (Object3D): 要添加的对象，这里为标记线网格
    // 返回值：无
    scene.add(marking);
  }

  // 创建简单的SUV汽车
  // 创建组对象
  // THREE.Group() - 创建组对象
  // 作用：将多个3D对象组合在一起，便于统一管理和变换
  // 参数：无
  // 返回值：THREE.Group实例
  car = new THREE.Group();

  // 创建汽车车身
  // 创建车身几何体
  // THREE.BoxGeometry() - 创建立方体几何体
  // 作用：定义汽车车身的3D形状，长方体作为车身基础
  // 参数：
  //   - width (number): X轴宽度，1.5单位
  //   - height (number): Y轴高度，0.6单位
  //   - depth (number): Z轴深度，0.8单位
  // 返回值：THREE.BoxGeometry实例
  const bodyGeometry: THREE.BoxGeometry = new THREE.BoxGeometry(1.5, 0.6, 0.8);
  // 创建车身材质
  // THREE.MeshStandardMaterial() - 创建标准材质
  // 作用：定义车身表面的外观特性，蓝色带有金属质感
  // 参数：
  //   - options (object): 材质配置选项
  //     - color (number): 基础颜色，十六进制值(0x0066cc)表示蓝色
  //     - roughness (number): 粗糙度，0.7表示中等粗糙
  //     - metalness (number): 金属度，0.3表示轻微金属感
  // 返回值：THREE.MeshStandardMaterial实例
  const bodyMaterial: THREE.MeshStandardMaterial = new THREE.MeshStandardMaterial({
    color: 0x0066cc,    // 蓝色
    roughness: 0.7,     // 中等粗糙度
    metalness: 0.3,     // 轻微金属感
  });
  // 创建车身网格对象
  // THREE.Mesh() - 创建网格对象
  // 作用：将车身几何体和材质结合，创建可渲染的车身
  // 参数：
  //   - geometry (Geometry): 几何体对象，这里为车身几何体
  //   - material (Material): 材质对象，这里为车身材质
  // 返回值：THREE.Mesh实例
  const carBody: THREE.Mesh = new THREE.Mesh(bodyGeometry, bodyMaterial);
  // 设置车身位置
  // carBody.position.y - 设置车身在Y轴的位置
  // 作用：调整车身在3D空间中的垂直位置，正值表示向上移动
  // 参数：
  //   - 直接赋值：position.y = 0.3 表示在Y轴向上移动0.3个单位
  // 返回值：无
  carBody.position.y = 0.3;
  // 将车身添加到汽车组
  // car.add() - 将对象添加到组中
  // 作用：将车身网格对象添加到汽车组中，成为汽车的一部分
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为车身网格
  // 返回值：无
  car.add(carBody);

  // 创建汽车车顶
  // 创建车顶几何体
  // THREE.BoxGeometry() - 创建立方体几何体
  // 作用：定义汽车车顶的3D形状，较小的长方体作为车顶
  // 参数：
  //   - width (number): X轴宽度，0.8单位
  //   - height (number): Y轴高度，0.3单位
  //   - depth (number): Z轴深度，0.7单位
  // 返回值：THREE.BoxGeometry实例
  const roofGeometry: THREE.BoxGeometry = new THREE.BoxGeometry(0.8, 0.3, 0.7);
  // 创建车顶材质
  // THREE.MeshStandardMaterial() - 创建标准材质
  // 作用：定义车顶表面的外观特性，与车身相同的蓝色材质
  // 参数：
  //   - options (object): 材质配置选项
  //     - color (number): 基础颜色，十六进制值(0x0066cc)表示蓝色
  //     - roughness (number): 粗糙度，0.7表示中等粗糙
  //     - metalness (number): 金属度，0.3表示轻微金属感
  // 返回值：THREE.MeshStandardMaterial实例
  const roofMaterial: THREE.MeshStandardMaterial = new THREE.MeshStandardMaterial({
    color: 0x0066cc,
    roughness: 0.7,
    metalness: 0.3,
  });
  // 创建车顶网格对象
  // THREE.Mesh() - 创建网格对象
  // 作用：将车顶几何体和材质结合，创建可渲染的车顶
  // 参数：
  //   - geometry (Geometry): 几何体对象，这里为车顶几何体
  //   - material (Material): 材质对象，这里为车顶材质
  // 返回值：THREE.Mesh实例
  const carRoof: THREE.Mesh = new THREE.Mesh(roofGeometry, roofMaterial);
  // 设置车顶位置
  // carRoof.position.set() - 设置车顶在3D空间中的位置
  // 作用：确定车顶相对于汽车组的位置，放置在车身之上
  // 参数：
  //   - x (number): X轴坐标，0表示在中心
  //   - y (number): Y轴坐标，0.75表示在车身之上
  //   - z (number): Z轴坐标，0表示在中心
  // 返回值：无
  carRoof.position.set(0, 0.75, 0);
  // 将车顶添加到汽车组
  // car.add() - 将对象添加到组中
  // 作用：将车顶网格对象添加到汽车组中，成为汽车的一部分
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为车顶网格
  // 返回值：无
  car.add(carRoof);

  // 创建汽车车轮
  // 创建车轮几何体
  // THREE.CylinderGeometry() - 创建圆柱体几何体
  // 作用：定义车轮的3D形状，圆柱体作为车轮基础
  // 参数：
  //   - radiusTop (number): 顶部半径，0.2单位
  //   - radiusBottom (number): 底部半径，0.2单位（与顶部相同，形成圆柱）
  //   - height (number): 高度，0.1单位（车轮厚度）
  //   - radialSegments (number): 径向分段数，16表示圆形较平滑
  //   - heightSegments (number, 可选): 高度分段数，默认1
  //   - openEnded (boolean, 可选): 是否开口，默认false
  //   - thetaStart (number, 可选): 起始角度，默认0
  //   - thetaLength (number, 可选): 角度范围，默认2π
  // 返回值：THREE.CylinderGeometry实例
  const wheelGeometry: THREE.CylinderGeometry = new THREE.CylinderGeometry(0.2, 0.2, 0.1, 16);
  // 创建车轮材质
  // THREE.MeshStandardMaterial() - 创建标准材质
  // 作用：定义车轮表面的外观特性，黑色橡胶质感
  // 参数：
  //   - options (object): 材质配置选项
  //     - color (number): 基础颜色，十六进制值(0x222222)表示深黑色
  //     - roughness (number): 粗糙度，0.9表示高粗糙度（橡胶质感）
  //     - metalness (number): 金属度，0.1表示低金属度
  // 返回值：THREE.MeshStandardMaterial实例
  const wheelMaterial: THREE.MeshStandardMaterial = new THREE.MeshStandardMaterial({
    color: 0x222222,    // 深黑色
    roughness: 0.9,     // 高粗糙度（橡胶质感）
    metalness: 0.1,     // 低金属度
  });

  // 定义四个车轮的位置坐标数组 [x, y, z]
  const wheelPositions: Array<[number, number, number]> = [
    [0.5, 0.2, 0.4],    // 右前轮
    [0.5, 0.2, -0.4],   // 右后轮
    [-0.5, 0.2, 0.4],   // 左前轮
    [-0.5, 0.2, -0.4],  // 左后轮
  ];

  // 遍历车轮位置数组，创建四个车轮
  wheelPositions.forEach(([x, y, z]) => {
    // 创建车轮网格对象
    // THREE.Mesh() - 创建网格对象
    // 作用：将车轮几何体和材质结合，创建可渲染的车轮
    // 参数：
    //   - geometry (Geometry): 几何体对象，这里为车轮几何体
    //   - material (Material): 材质对象，这里为车轮材质
    // 返回值：THREE.Mesh实例
    const wheel: THREE.Mesh = new THREE.Mesh(wheelGeometry, wheelMaterial);
    // 旋转车轮
    // wheel.rotation.x - 设置车轮绕X轴的旋转
    // 作用：调整车轮方向，使圆柱体平放（原本圆柱体是立着的）
    // 参数：
    //   - 直接赋值：rotation.x = Math.PI / 2 表示绕X轴旋转90度
    // 返回值：无
    wheel.rotation.x = Math.PI / 2;
    // 设置车轮位置
    // wheel.position.set() - 设置车轮在3D空间中的位置
    // 作用：确定每个车轮在汽车组中的具体位置
    // 参数：
    //   - x (number): X轴坐标，从wheelPositions数组获取
    //   - y (number): Y轴坐标，从wheelPositions数组获取
    //   - z (number): Z轴坐标，从wheelPositions数组获取
    // 返回值：无
    wheel.position.set(x, y, z);
    
    // 为每个车轮添加一条红色标记线，用于更明显地显示车轮旋转
    // 创建标记线几何体
    // THREE.BoxGeometry() - 创建立方体几何体
    // 作用：定义车轮标记线的3D形状，细长长方体作为标记
    // 参数：
    //   - width (number): X轴宽度，0.3单位
    //   - height (number): Y轴高度，0.1单位
    //   - depth (number): Z轴深度，0.1单位
    // 返回值：THREE.BoxGeometry实例
    const lineGeometry: THREE.BoxGeometry = new THREE.BoxGeometry(0.3, 0.1, 0.1);
    // 创建标记线材质
    // THREE.MeshBasicMaterial() - 创建基础材质
    // 作用：定义标记线外观，不受光照影响，醒目的红色
    // 参数：
    //   - options (object): 材质配置选项
    //     - color (number): 颜色，十六进制值(0xff0000)表示红色
    // 返回值：THREE.MeshBasicMaterial实例
    const lineMaterial: THREE.MeshBasicMaterial = new THREE.MeshBasicMaterial({
      color: 0xff0000,  // 红色
    });
    // 创建标记线网格对象
    // THREE.Mesh() - 创建网格对象
    // 作用：将标记线几何体和材质结合，创建可渲染的标记线
    // 参数：
    //   - geometry (Geometry): 几何体对象，这里为标记线几何体
    //   - material (Material): 材质对象，这里为标记线材质
    // 返回值：THREE.Mesh实例
    const line: THREE.Mesh = new THREE.Mesh(lineGeometry, lineMaterial);
    // 设置标记线位置
    // line.position.set() - 设置标记线在车轮局部空间中的位置
    // 作用：确定标记线相对于车轮的位置，从中心延伸到边缘
    // 参数：
    //   - x (number): X轴坐标，0.1表示在车轮半径方向偏移
    //   - y (number): Y轴坐标，0表示在中心
    //   - z (number): Z轴坐标，0表示在中心
    // 返回值：无
    line.position.set(0.1, 0, 0);
    // 将标记线添加为车轮的子对象
    // wheel.add() - 将对象添加为子对象
    // 作用：将标记线网格对象添加为车轮的子对象，继承车轮的变换（随车轮一起旋转）
    // 参数：
    //   - object (Object3D): 要添加的对象，这里为标记线网格
    // 返回值：无
    wheel.add(line);

    // 将车轮添加到汽车组
    // car.add() - 将对象添加到组中
    // 作用：将车轮网格对象添加到汽车组中，成为汽车的一部分
    // 参数：
    //   - object (Object3D): 要添加的对象，这里为车轮网格
    // 返回值：无
    car.add(wheel);
  });

  // 将汽车放置在道路上并旋转使其面向左侧
  // 设置汽车位置
  // car.position.set() - 设置汽车在3D空间中的位置
  // 作用：确定汽车在场景中的初始位置，放置在道路上
  // 参数：
  //   - x (number): X轴坐标，0表示在场景中心
  //   - y (number): Y轴坐标，-0.5表示略低于道路表面
  //   - z (number): Z轴坐标，0表示在道路中央
  // 返回值：无
  car.position.set(0, -0.5, 0);
  // 将汽车添加到场景
  // scene.add() - 将对象添加到场景中
  // 作用：将汽车组对象添加到场景中进行渲染
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为汽车组
  // 返回值：无
  scene.add(car);

  // 设置相机位置
  // camera.position.set() - 设置相机在3D空间中的位置
  // 作用：确定相机的观察位置，从上方和后方观察场景
  // 参数：
  //   - x (number): X轴坐标，0表示在中心
  //   - y (number): Y轴坐标，3表示在上方
  //   - z (number): Z轴坐标，8表示在后方
  // 返回值：无
  camera.position.set(0, 3, 8);
  // 设置相机看向点
  // camera.lookAt() - 设置相机注视的目标点
  // 作用：让相机朝向指定的3D坐标点，这里看向场景中心
  // 参数：
  //   - x (number): X轴坐标，0表示场景中心
  //   - y (number): Y轴坐标，0表示场景中心
  //   - z (number): Z轴坐标，0表示场景中心
  // 或者使用 Vector3 对象
  // 返回值：无
  camera.lookAt(0, 0, 0);

  // 创建网格辅助器
  // THREE.GridHelper() - 创建网格辅助器对象
  // 作用：在场景中显示参考网格，便于可视化3D空间和定位
  // 参数：
  //   - size (number): 网格大小，20单位
  //   - divisions (number): 分割数，20表示有20个格子
  //   - colorCenterLine (number): 中心线颜色，十六进制值(0x444444)表示深灰色
  //   - colorGrid (number): 网格线颜色，十六进制值(0x222222)表示更深的灰色
  // 返回值：THREE.GridHelper实例
  const gridHelper: THREE.GridHelper = new THREE.GridHelper(20, 20, 0x444444, 0x222222);
  // 设置网格辅助器位置
  // gridHelper.position.y - 设置网格在Y轴的位置
  // 作用：调整网格在3D空间中的垂直位置，与道路表面对齐
  // 参数：
  //   - 直接赋值：position.y = -1 表示在Y轴向下移动1个单位
  // 返回值：无
  gridHelper.position.y = -1;
  // 将网格辅助器添加到场景
  // scene.add() - 将对象添加到场景中
  // 作用：将网格辅助器对象添加到场景中进行渲染和参考
  // 参数：
  //   - object (Object3D): 要添加的对象，这里为网格辅助器
  // 返回值：无
  scene.add(gridHelper);
};

// 动画循环函数
const animate = (): void => {
  // 请求动画帧
  // requestAnimationFrame() - 浏览器API，请求下一帧动画
  // 作用：在浏览器下次重绘前调用指定的回调函数，形成平滑的动画循环
  // 参数：
  //   - callback (function): 回调函数，这里为animate函数
  // 返回值：number - 请求ID，用于取消动画
  animationId = requestAnimationFrame(animate);

  // 移动汽车位置
  // car.position.x -= 0.05 - 修改汽车在X轴的位置
  // 作用：每帧将汽车向左移动0.05单位，创造行驶动画效果
  // 参数：
  //   - 直接操作：position.x -= 0.05 表示X坐标减少0.05（向左移动）
  // 返回值：无
  car.position.x -= 0.05;

  // 检查汽车位置并重置
  // 条件判断和位置重置
  // 作用：当汽车移动出左边界时，将其重置到右边界，实现循环行驶
  // 参数：
  //   - car.position.x < -10: 检查汽车是否超出左边界(-10)
  //   - car.position.x = 10: 将汽车位置重置到右边界(10)
  // 返回值：无
  if (car.position.x < -10) {
    car.position.x = 10;
  }

  // 旋转车轮（围绕y轴旋转），创建车轮滚动的效果
  // 遍历汽车的所有子对象
  car.children.forEach((child) => {
    // 检查子对象类型
    // instanceof 操作符 - 检查对象是否为特定类的实例
    // 作用：筛选出车轮对象（网格对象且几何体为圆柱体）
    // 参数：无
    // 返回值：boolean - 如果是车轮返回true
    if (child instanceof THREE.Mesh && child.geometry instanceof THREE.CylinderGeometry) {
      // 旋转车轮
      // child.rotation.y += 0.1 - 修改车轮绕Y轴的旋转
      // 作用：每帧将车轮绕Y轴旋转0.1弧度，创造车轮滚动效果
      // 参数：
      //   - 直接操作：rotation.y += 0.1 表示Y轴旋转增加0.1弧度
      // 返回值：无
      child.rotation.y += 0.1;
    }
  });

  // 渲染场景
  // renderer.render() - 渲染3D场景
  // 作用：将场景中的对象通过相机视角渲染到canvas中，显示最终图像
  // 参数：
  //   - scene (Scene): 要渲染的场景对象
  //   - camera (Camera): 用于渲染的相机对象
  // 返回值：无
  renderer.render(scene, camera);
};

// 窗口大小改变处理函数
const handleResize = (): void => {
  // 检查相机和渲染器是否已初始化
  if (!camera || !renderer) {return;}
  // 更新相机宽高比
  // camera.aspect - 设置相机的宽高比属性
  // 作用：根据窗口尺寸调整相机宽高比，防止图像拉伸变形
  // 参数：
  //   - 直接赋值：aspect = window.innerWidth / window.innerHeight 计算新的宽高比
  // 返回值：无
  camera.aspect = window.innerWidth / window.innerHeight;
  // 更新相机投影矩阵
  // camera.updateProjectionMatrix() - 更新相机的投影矩阵
  // 作用：当相机参数（如宽高比）改变后，必须调用此方法重新计算投影矩阵
  // 参数：无
  // 返回值：无
  camera.updateProjectionMatrix();
  // 更新渲染器大小
  // renderer.setSize() - 设置渲染器的输出canvas大小
  // 作用：当窗口尺寸改变时，调整渲染器绘制区域的大小
  // 参数：
  //   - width (number): 宽度像素值，使用窗口内宽
  //   - height (number): 高度像素值，使用窗口内高
  // 返回值：无
  renderer.setSize(window.innerWidth, window.innerHeight);
};

// Vue组件挂载生命周期钩子
// 当组件被挂载到DOM时执行
onMounted(() => {
  initThreeJS();  // 初始化Three.js场景
  animate();      // 开始动画循环
  // 添加窗口大小改变事件监听器
  window.addEventListener('resize', handleResize);
});

// Vue组件卸载生命周期钩子
// 当组件从DOM中移除时执行（清理工作）
onUnmounted(() => {
  // 移除窗口大小改变事件监听器
  window.removeEventListener('resize', handleResize);
  // 取消动画帧
  // cancelAnimationFrame() - 浏览器API，取消动画帧请求
  // 作用：停止动画循环，释放资源
  // 参数：
  //   - animationId (number): 之前requestAnimationFrame返回的ID
  // 返回值：无
  if (animationId) {
    cancelAnimationFrame(animationId);
  }
  // 清理Three.js资源
  if (renderer && container.value) {
    // 从DOM移除canvas元素
    // container.value.removeChild() - DOM操作方法
    // 作用：将Three.js渲染器的canvas元素从页面中移除
    // 参数：
    //   - renderer.domElement: 渲染器的canvas DOM元素
    // 返回值：无
    container.value.removeChild(renderer.domElement);
    // 释放渲染器资源
    // renderer.dispose() - 释放渲染器占用的资源
    // 作用：清理WebGL上下文、着色器程序等，防止内存泄漏
    // 参数：无
    // 返回值：无
    renderer.dispose();
  }
});
</script>

<style scoped>
/* 样式部分：设置容器样式 */
.car-road-container {
  width: 100%;        /* 宽度100%填充父容器 */
  height: 100vh;      /* 高度100%视口高度 */
  margin: 0;          /* 外边距为0 */
  padding: 0;         /* 内边距为0 */
  overflow: hidden;   /* 隐藏溢出内容 */
  background-color: #87ceeb; /* 天蓝色背景，模拟天空 */
}
</style>